/*
 * This file is part of ELCube.
 *
 * ELCube is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ELCube is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with ELCube.  If not, see <https://www.gnu.org/licenses/>.
 */
package cn.nkpro.elcube.security;

import cn.nkpro.elcube.data.redis.RedisSupport;
import cn.nkpro.elcube.security.validate.*;
import cn.nkpro.elcube.security.validate2.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import java.util.List;

/**
 * Created by bean on 2019/12/30.
 */
@Configuration
@EnableGlobalMethodSecurity(securedEnabled=true,prePostEnabled = true)
public class NkWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @SuppressWarnings("all")
    @Autowired
    private UserAccountService userDetailsService;

    @SuppressWarnings("all")
    @Autowired
    private List<NkCodeUserDetailsService> userDetailsServices;

    @Autowired
    private AuthenticationUtils authenticationUtils;

    @SuppressWarnings("all")
    @Autowired
    private RedisSupport<Object> redisSupport;

    @Autowired
    private List<AuthenticationFilterV2> authenticationFilterV2List;

    private NkAuthenticationEntryPoint nkAuthenticationEntryPoint = new NkAuthenticationEntryPoint();

    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        // 兼容老版本
        auth.authenticationProvider(new NkUsernamePasswordAuthenticationProvider(userDetailsService,redisSupport));
        auth.authenticationProvider(new NkUsernamePasswordVerCodeAuthenticationProvider(userDetailsService,redisSupport));
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            .headers()
                .frameOptions()
                .sameOrigin()
                .and()

            // 兼容老版本
            .addFilterBefore(new NkJWTAuthenticationFilter(authenticationManager(),nkAuthenticationEntryPoint), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(new NkUsernamePasswordVerCodeAuthenticationFilter(authenticationManager(),nkAuthenticationEntryPoint), UsernamePasswordAuthenticationFilter.class)
            // Basic验证，不推荐使用，仅仅为了方便调试
            .addFilterBefore(new BasicAuthenticationFilter(authenticationManager(),nkAuthenticationEntryPoint), UsernamePasswordAuthenticationFilter.class)

            .exceptionHandling()
            .accessDeniedHandler(new NkAccessDeniedHandler())
            .authenticationEntryPoint(nkAuthenticationEntryPoint)
            .and()
        ;

        /*
         * 1、通过用户名密码换取token
         * 2、通过手机号验证码换取token
         * 3、通过第三方code获取token
         * 4、通过secret签名免登陆
         * 5、通过token签名访问
         * 6、通过用户名密码换取token（不推荐，兼容老版本）
         * 7、通过token直接访问（不推荐，兼容老版本）
         */
        authenticationFilterV2List.forEach(filter->http.addFilterBefore(filter, NkJWTAuthenticationFilter.class));
    }

    @ConditionalOnMissingBean
    @Bean
    protected UserBusinessAdapter userBusinessAdapter(){
        return new UserBusinessAdapter(){};
    }
}
